package com.project.web.system.controller.common;

import com.alibaba.fastjson.JSON;
import com.project.common.core.utils.OssUtils;
import com.project.common.core.utils.exception.CustomException;
import com.project.common.core.utils.exception.RESP_CODE_ENUM;
import com.project.common.core.utils.exception.Result;
import com.project.common.core.utils.redis.RedisClient;
import com.project.common.core.utils.redis.RedisConsts;
import com.project.common.core.utils.user.PropConsts;
import com.project.web.system.model.app.Admin;
import com.project.web.system.model.app.ApiToken;
import com.project.web.system.service.app.AdminService;
import com.project.web.system.service.app.ApiTokenService;
import com.project.web.system.service.app.SMSService;
import com.project.web.util.Setting;
import com.project.web.util.SettingUtils;
import com.project.web.util.exception.SYSTEM_RESP_CODE_ENUM;
import com.project.web.util.exception.SystemCustomException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 后台公用controller
 */
@Api(tags = "公共接口")
@RestController("systemServiceCommonController")
@RequestMapping("/system/common")
public class CommonController extends BaseController {
    private static final long serialVersionUID = -7624305021416504596L;

    @Resource(name = "redisClient")
    private RedisClient redisClient;

    @Resource(name = "SMSServiceImpl")
    private SMSService smsService;

    @Resource(name = "apiTokenServiceImpl")
    private ApiTokenService apiTokenService;

    @Resource(name = "sysUserServiceImpl")
    private AdminService sysUserService;

    /**
     * 获取接口令牌
     *
     * @param apiId     api标识
     * @param apiSecret api密钥
     * @return
     */
    @ApiOperation(value = "获取API令牌", notes = "获取API令牌", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "apiId", value = "api标识", dataType = "Long"),
            @ApiImplicitParam(name = "apiSecret", value = "api密钥", dataType = "String"),
    })
    @GetMapping(value = "/getApiToken")
    public Result<Map<String, Object>> getApiToken(Long apiId, String apiSecret) {
        // 校验参数
        if (apiId == null || StringUtils.isBlank(apiSecret)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }

        // 查询api令牌
        ApiToken apiToken = new ApiToken();
        apiToken.setApiId(apiId);
        List<ApiToken> apiTokens = apiTokenService.selectList(apiToken);
        if (CollectionUtils.isEmpty(apiTokens)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.REQUIRED_IDENTIFY_NOT_EXIST);
        }

        // 判断密钥是否正确
        String apiSecretMd5 = DigestUtils.md5Hex(apiTokens.get(0).getApiSecret());
        if (!StringUtils.equals(apiSecretMd5, apiSecret)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.PWD_ERROR);
        }

        // 放入redis
        String apiTokenStr = RandomStringUtils.randomNumeric(10);
        String returnAppId = apiId + apiTokenStr;
        redisClient.set(RedisConsts.API_TOKEN_KEY + returnAppId, apiTokenStr, RedisConsts.API_TOKEN_EXPIRE);

        // 初始化返回参数
        Map<String, Object> resultMap = new HashMap();
        resultMap.put("apiToken", apiTokenStr);
        resultMap.put("apiId", returnAppId);
        return getResult(resultMap);
    }

    /**
     * 用户登录
     *
     * @param sysUser 登录用户名称
     * @return
     */
    @ApiOperation(value = "用户登录")
    @PostMapping(value = "/login")
    public Result<Admin> login(@RequestBody Admin sysUser) {

        String userName = sysUser.getUsername();
        String loginPwd = sysUser.getLoginPwd();
        // 参数校验
        if (StringUtils.isBlank(userName) || StringUtils.isBlank(loginPwd)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }

        // 校验用户是否纯在
        Admin sysUserDb = sysUserService.getByUserName(userName);
        if (sysUserDb == null) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.ACCT_NOT_EXIST);
        }

        // 校验密码
        String pwdDb = sysUserDb.getLoginPwd();
        String pwdMd5 = DigestUtils.md5Hex(loginPwd);
        if (!StringUtils.equalsIgnoreCase(pwdDb, pwdMd5)) {
            throw new CustomException(RESP_CODE_ENUM.PWD_ERROR);
        }
        return getResult(sysUserDb);
    }

    /**
     * 获取手机号通用验证码
     *
     * @param phone 手机验证码
     * @return
     */
    @ApiOperation(value = "获取手机号通用验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String")
    })
    @GetMapping(value = "/getMobileCodeOfGeneral")
    public Result<String> getMobileCodeOfGeneral(String phone) {
        // 参数校验
        if (StringUtils.isBlank(phone)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }

        // 查询验证码是否存在
        Object codeObject = redisClient.get(RedisConsts.MEMBER_MOBILE_CODE + phone);
        if (null != codeObject && StringUtils.isNotBlank(codeObject.toString())) {
            return getResult(String.valueOf(codeObject));
        }

        //生成验证码
        String captcha = RandomStringUtils.randomNumeric(6);
        log.info("\r\n *********验证码{}:{}*********", phone, captcha);
        smsService.sendAliSMSForFGeneral("86", phone, captcha, "1");
        return getResult(captcha);
    }

    /**
     * 获取国际手机号通用验证码
     *
     * @param phone    手机验证码
     * @param areaCode 区号
     * @return
     */
    @ApiOperation(value = "获取国际手机号通用验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "areaCode", value = "国际区号", dataType = "String"),
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String")
    })
    @GetMapping(value = "/getInternationalMobileCode")
    public Result<String> getInternationalMobileCode(String areaCode, String phone) {
        // 参数校验
        if (StringUtils.isBlank(phone)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PHONE);
        }
        if (StringUtils.isBlank(areaCode)) {
            areaCode = "86";
        }

        // 查询验证码是否存在
        Object codeObject = redisClient.get(RedisConsts.MEMBER_MOBILE_CODE + areaCode + ":" + phone);
        if (null != codeObject && StringUtils.isNotBlank(codeObject.toString())) {
            return getResult(String.valueOf(codeObject));
        }

        //生成验证码
        String captcha = RandomStringUtils.randomNumeric(6);
        log.info("\r\n *********验证码{}:{}*********", phone, captcha);
        //中国国际区号
        if (areaCode.equals("86")) {
            smsService.sendAliSMSForFGeneral(areaCode, phone, captcha, "1");
        } else {
            smsService.sendAliSMSForFGeneral(areaCode, phone, captcha, "2");
        }
        return getResult(captcha);
    }

    /**
     * 校验手机号验证码
     *
     * @param phone 手机验证码
     * @return
     */
    @ApiOperation(value = "校验手机号验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String"),
            @ApiImplicitParam(name = "phoneCode", value = "验证码", dataType = "String"),
    })
    @GetMapping(value = "/checkPhoneCode")
    public Result<String> checkPhoneCode(String phone, String phoneCode, String areaCode) {
        if (StringUtils.isBlank(areaCode)) {
            checkPhoneVerificationCode("86", phone, phoneCode);
        } else {
            checkPhoneVerificationCode(areaCode, phone, phoneCode);
        }
        return getResult("success");
    }

    /**
     * 发送头条推广短信通知
     *
     * @param phone 手机号
     * @param wxNum 微信号
     * @return
     */
    @ApiOperation(value = "发送头条推广短信")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String"),
            @ApiImplicitParam(name = "wxNum", value = "微信号", dataType = "String"),
    })
    @GetMapping(value = "/sendWxNumOfZj")
    public Result<String> sendMsgOfZj(String phone, String wxNum) {
        // 参数校验
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(wxNum)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }

        //生成验证码
        smsService.sendAliSMSOfWxNum(phone, wxNum);
        return getResult("success");
    }

    /**
     * 重置密码
     *
     * @return
     */
    @ApiOperation(value = "重置秘密")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Long"),
    })
    @GetMapping(value = "/resetPwd")
    public Result<Admin> resetPassword(String userId) {

        // 参数校验
        if (StringUtils.isBlank(userId)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }

        String defautlPwd = DigestUtils.md5Hex(PropConsts.DEFAUTL_PWD);

        Admin sysUser = new Admin();
        sysUser.setUserId(Long.valueOf(userId));
        sysUser.setLoginPwd(defautlPwd);
        sysUserService.update(sysUser);
        return getResult(null);
    }

    /**
     * 修改密码
     *
     * @return
     */
    @ApiOperation(value = "修改密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Long"),
    })
    @PostMapping(value = "/changePwd")
    public Result<Admin> changePwd(@RequestBody Admin sysUser) {

        String loginPwd = sysUser.getLoginPwd();

        // 参数校验
        if (StringUtils.isBlank(loginPwd) || StringUtils.isBlank(String.valueOf(sysUser.getUserId()))) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }
        String newPwd = DigestUtils.md5Hex(loginPwd);
        sysUser.setLoginPwd(newPwd);
        sysUserService.update(sysUser);
        return getResult(null);
    }

    //短信校验
    private void checkPhoneVerificationCode(String areaCode, String phone, String phoneCode) {
        // 参数校验
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(phoneCode)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }

        // 查询验证码是否存在
        Object codeObject = redisClient.get(RedisConsts.MEMBER_MOBILE_CODE + areaCode + ":" + phone);
        if (null == codeObject) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.CAPTCHA_CODE_INVALID);
        }

        // 验证码校验
        String redisCode = String.valueOf(codeObject);
        if (!StringUtils.equalsIgnoreCase(phoneCode, redisCode)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.CAPTCHA_CODE_ERROR);
        }

        // 删除验证码
        redisClient.del(RedisConsts.MEMBER_MOBILE_CODE + areaCode + ":" + phone);

    }

    /**
     * 系统参数
     *
     * @return
     */
    @ApiOperation(value = "系统参数")
    @GetMapping(value = "/systemConfig")
    public Result<Map> systemConfig() {
        Setting setting = SettingUtils.get();
        Map map = JSON.parseObject(JSON.toJSONString(setting), Map.class);
        return getResult(map);
    }

    /**
     * 上传文件到OSS,返回文件目录地址
     *
     * @param file 文件
     * @return
     */
    @ApiOperation(value = "上传文件到OSS,返回文件目录地址", notes = "fileCode 标识: 100:学院课, 101:晋级课 102:专项课 103:课程分类 104:临时文件夹 105:打卡海报 106:内容发布管理")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "file", value = "上传文件", required = true, dataType = "MultipartFile"),
            @ApiImplicitParam(paramType = "query", name = "fileCode", value = "上传文件", required = false, dataType = "Integer")
    })
    @PostMapping(value = "/uploadFile")
    public Result<String> uploadFile(MultipartFile file, Integer fileCode) {
        // 参数校验
        if (null == fileCode || fileCode.equals(null)) {
            throw new SystemCustomException(SYSTEM_RESP_CODE_ENUM.MISS_PARAMETER);
        }
        try {
            return getResult(OssUtils.upLoad(file.getInputStream(), fileCode, file.getOriginalFilename()));
        } catch (IOException e) {
            log.error("上传文件到OSS出错:{}", ExceptionUtils.getFullStackTrace(e));
        }
        return getResult(null);
    }

}
